home *** CD-ROM | disk | FTP | other *** search
- /*
-
- Finder Marquee
- by Jordan Zimmerman
- (c)1995 by Altura Software, Inc.
-
- Unlimited use is hereby granted without restriction. However,
- the author would appreciate credit if possible. Please send
- comments, questions, bugs, etc. to jordanz@altura.com
-
- This code implements a "rubber band" marquee select rect
- with very smooth drawing in a manner similar to the Mac Finder.
-
- Change History:
-
- 1.0.0 07/10/95 JLZ Created inital C version from existing C++ framework
-
- */
-
- #include "finder_marquee.h"
-
- static void calculate_marquee_r(finder_marquee_rec* marquee_ptr);
- static void draw_marquee_r(const finder_marquee_rec* marquee_ptr);
- static void make_frame_region(RgnHandle target_rgn_h, const Rect* frame_r_ptr, RgnHandle work_rgn_h);
-
-
- //-------------Global Functions------------
-
-
- void FinderMarqueeBegin(finder_marquee_rec* marquee_ptr, Point mouse_down_pt)
- {
-
- // save the first mouse as our anchor point
- marquee_ptr->pin_pt = mouse_down_pt;
-
- // it's also our current point
- marquee_ptr->current_pt = mouse_down_pt;
-
- // make the marquee_r
- calculate_marquee_r(marquee_ptr);
-
- // allow selections to draw now to avoid and screen turds
- if ( marquee_ptr->change_selection_proc )
- {
- Rect old_marquee_r = marquee_ptr->marquee_r;
- marquee_ptr->change_selection_proc(marquee_ptr, &old_marquee_r);
- }
-
- // display the first marquee_r - important to have a balance when FinderMarqueeEnd is called
- draw_marquee_r(marquee_ptr);
-
- } // FinderMarqueeBegin
-
- void FinderMarqueeEnd(finder_marquee_rec* marquee_ptr)
- {
-
- // remove the marquee from the screen -
- // this works because FinderMarqueeBegin drew it
- draw_marquee_r(marquee_ptr);
-
- } // FinderMarqueeEnd
-
- void FinderMarqueeContinue(finder_marquee_rec* marquee_ptr, Point new_mouse_pt)
- {
-
- PenState pen_state;
- Rect old_marquee_r;
- RgnHandle old_rgn_h = NULL;
- RgnHandle work_rgn_h = NULL;
- RgnHandle new_rgn_h = NULL;
- RgnHandle clip_rgn_h = NULL;
- int success_flag = false;
-
- // avoid flashing step 1 - do nothing if the mouse hasn't moved
- if ( EqualPt(new_mouse_pt, marquee_ptr->current_pt) )
- {
- return;
- }
- clip_rgn_h = NewRgn();
- if ( !clip_rgn_h )
- {
- return; // can't find 10 bytes! We're probably already in big trouble
- }
-
- // we'll be messing with the clip, so save it for later restoration
- GetClip(clip_rgn_h);
-
- // save and setup the pen
- GetPenState(&pen_state);
- PenMode(patXor);
- PenPat(&qd.gray);
-
- // save the old marquee_r and setup the new one
- old_marquee_r = marquee_ptr->marquee_r;
- marquee_ptr->current_pt = new_mouse_pt;
- calculate_marquee_r(marquee_ptr);
-
- do
- {
- old_rgn_h = NewRgn();
- if ( !old_rgn_h )
- {
- break;
- }
- work_rgn_h = NewRgn();
- if ( !work_rgn_h )
- {
- break;
- }
- new_rgn_h = NewRgn();
- if ( !new_rgn_h )
- {
- break;
- }
-
- // generate 1 pixel thick outline regions of the old and new marquee_r
- make_frame_region(old_rgn_h, &old_marquee_r, work_rgn_h);
- make_frame_region(new_rgn_h, &marquee_ptr->marquee_r, work_rgn_h);
-
- // get the area in common between the old and the new
- SectRgn(old_rgn_h, new_rgn_h, work_rgn_h);
-
- // set the clip to the old clip minus the common area of the old and new marquee rect
- DiffRgn(clip_rgn_h, work_rgn_h, work_rgn_h);
- SetClip(work_rgn_h);
-
- if ( marquee_ptr->selections_proc && marquee_ptr->selections_proc(marquee_ptr) )
- {
- // If there is a selection, the old marquee must be erased, the selections must be drawn,
- // and then the new marquee can be drawn.
- FrameRect(&old_marquee_r);
- if ( marquee_ptr->change_selection_proc )
- {
- marquee_ptr->change_selection_proc(marquee_ptr, &old_marquee_r);
- }
- FrameRect(&marquee_ptr->marquee_r);
- }
- else
- {
- // If there's no selection change, the marquee can be drawn in one step
- // that will erase the old and draw the new.
- UnionRgn(new_rgn_h, old_rgn_h, work_rgn_h);
- PaintRgn(work_rgn_h); // this will both erase the old and draw the new
- }
- } while ( success_flag++ ); // i.e. do once, set success_flag on exit
-
- if ( !success_flag )
- {
- // memory is evidently very tight, we'll have to live with flashing
- FrameRect(&old_marquee_r);
- if ( marquee_ptr->change_selection_proc )
- {
- marquee_ptr->change_selection_proc(marquee_ptr, &old_marquee_r);
- }
- FrameRect(&marquee_ptr->marquee_r);
- }
-
- // restore clip and pen and then cleanup
-
- SetClip(clip_rgn_h);
- SetPenState(&pen_state);
-
- if ( old_rgn_h )
- {
- DisposeRgn(old_rgn_h);
- }
- if ( work_rgn_h )
- {
- DisposeRgn(work_rgn_h);
- }
- if ( new_rgn_h )
- {
- DisposeRgn(new_rgn_h);
- }
- if ( clip_rgn_h )
- {
- DisposeRgn(clip_rgn_h);
- }
-
- } // FinderMarqueeContinue
-
-
- //-------------Local Functions-------------
-
-
- // calculating the marquee rect isn't as simple as Pt2Rect. Using Pt2Rect
- // causes the pin point to shift around. This function will calculate a
- // correct marquee rect that keeps the pin point in place
- static void calculate_marquee_r(finder_marquee_rec* marquee_ptr)
- {
-
- if ( (marquee_ptr->current_pt.h >= marquee_ptr->pin_pt.h) && (marquee_ptr->current_pt.v >= marquee_ptr->pin_pt.v) ) // Quadrant IV
- {
- SetRect(&marquee_ptr->marquee_r, marquee_ptr->pin_pt.h, marquee_ptr->pin_pt.v, marquee_ptr->current_pt.h + 1, marquee_ptr->current_pt.v + 1);
- }
- else if ( (marquee_ptr->current_pt.h <= marquee_ptr->pin_pt.h) && (marquee_ptr->current_pt.v <= marquee_ptr->pin_pt.v) ) // Quadrant I
- {
- SetRect(&marquee_ptr->marquee_r, marquee_ptr->current_pt.h, marquee_ptr->current_pt.v, marquee_ptr->pin_pt.h + 1, marquee_ptr->pin_pt.v + 1);
- }
- else if ( (marquee_ptr->current_pt.h >= marquee_ptr->pin_pt.h) && (marquee_ptr->current_pt.v <= marquee_ptr->pin_pt.v) ) // Quadrant II
- {
- SetRect(&marquee_ptr->marquee_r, marquee_ptr->pin_pt.h, marquee_ptr->current_pt.v, marquee_ptr->current_pt.h + 1, marquee_ptr->pin_pt.v + 1);
- }
- else // Quadrant III
- {
- SetRect(&marquee_ptr->marquee_r, marquee_ptr->current_pt.h, marquee_ptr->pin_pt.v, marquee_ptr->pin_pt.h + 1, marquee_ptr->current_pt.v + 1);
- }
-
- } // calculate_marquee_r
-
- // outline the marquee rect in Xor gray
- static void draw_marquee_r(const finder_marquee_rec* marquee_ptr)
- {
-
- PenState pen_state;
- GetPenState(&pen_state);
-
- PenMode(patXor);
- PenPat(&qd.gray);
-
- FrameRect(&marquee_ptr->marquee_r);
-
- SetPenState(&pen_state);
-
- } // draw_marquee_r
-
- // utility to make a 1 pixel thick region of the frame outline of a rect
- static void make_frame_region(RgnHandle target_rgn_h, const Rect* frame_r_ptr, RgnHandle work_rgn_h)
- {
-
- RectRgn(target_rgn_h, frame_r_ptr);
- CopyRgn(target_rgn_h, work_rgn_h);
- InsetRgn(work_rgn_h, 1, 1);
- DiffRgn(target_rgn_h, work_rgn_h, target_rgn_h);
-
- } // make_frame_region
-